#include "Demo_Client.h"

DemoClient::GameClientListener::GameClientListener( DemoClient *demoClient  ) :
mDemoClient( demoClient )
{
}

DemoClient::GameClientListener::~GameClientListener()
{
}

void DemoClient::GameClientListener::onAtmosPacket( ATMOS::Packet *packet )
{
}

void DemoClient::GameClientListener::onDisconnectionNotification( const std::string &senderGUID ) 
{
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onAlreadyConnected( const std::string &senderGUID )
{
}

void DemoClient::GameClientListener::onIncompatibleProtocolVersion( const std::string &senderGUID )
{
}

void DemoClient::GameClientListener::onRemoteDisconnectionNotification( const std::string &senderGUID ) 
{
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onRemoteConnectionLost( const std::string &senderGUID )
{
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onNewIncomingConnection( const std::string &senderGUID ) 
{
}

void DemoClient::GameClientListener::onConnectionBanned( const std::string &senderGUID )
{	
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onConnectionAttemptFailed( const std::string &senderGUID )
{
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onNoFreeIncomingConnections( const std::string &senderGUID )
{
}

void DemoClient::GameClientListener::onInvalidPassword( const std::string &senderGUID )
{
}

void DemoClient::GameClientListener::onConnectionLost( const std::string &senderGUID ) 
{
	mDemoClient->mConnectedToGameServer = false;
}

void DemoClient::GameClientListener::onConnectionRequestAccepted( const std::string &senderGUID )
{
	mDemoClient->mConnectedToGameServer = true;
	mDemoClient->mGameServerGUID = senderGUID;

	// register with the game server
	ATMOS::Packet p( ATMOS::API_REGISTER_CLIENT, mDemoClient->mClient.getLocalGUID() );
	p.writeString( mDemoClient->mClient.getLocalGUID() );
	mDemoClient->mClient.broadcastPacket( &p );
}

void DemoClient::GameClientListener::onUnknownPacket( const std::string &senderGUID )
{
}

DemoClient::MSClientListener::MSClientListener( DemoClient *demoClient, const std::string &name, 
	int gamePort, int gameServerPort ) :
mDemoClient( demoClient ),
mName( name ),
mPort( gamePort ),
mGameServerPort( gameServerPort )
{
}

DemoClient::MSClientListener::~MSClientListener()
{
}

void DemoClient::MSClientListener::onAtmosPacket( ATMOS::Packet *packet )
{
	switch( packet->getAtmosPacketID() )
	{
	case ATMOS::API_MASTER_SERVER:
		{
			ATMOS::PacketID mspid = (ATMOS::PacketID)packet->readUChar();
			switch( mspid )
			{
			case ATMOS::MSPID_CL_GAME_CONNECTION_APPROVED:
				{
					std::cout << "MSPID_CL_GAME_CONNECTION_APPROVED" << std::endl;
				
					ATMOS::NetworkConnectionInfo info;
					//info.serverIP = "127.0.0.1";
					info.serverIP = packet->readString();
					info.serverPort = mGameServerPort;
					info.clientPort = mPort;

					std::string clientGUID = packet->readString();
					std::string serverGUID = packet->readString();

					mDemoClient->mClient.initialize( info );
					mDemoClient->mClientInitialized = true;
					mDemoClient->mClient.addPacketListener( mDemoClient->mGameClientListener );
				}
				break;
			case ATMOS::MSPID_CL_GAME_CONNECTION_DENIED:
				std::cout << "MSPID_CL_GAME_CONNECTION_DENIED" << std::endl;
				break;
			}
		}
	case ATMOS::API_DEBUG_1:
		std::cout << "DEBUG CLIENT CHAT: " << packet->readString() << std::endl;
		break;
	case ATMOS::API_DEBUG_2:
		std::cout << "***ERROR GOT SERVER CHAT: " << packet->readString() << std::endl;
		break;
	}
}

void DemoClient::MSClientListener::onDisconnectionNotification( const std::string &senderGUID )
{
}

void DemoClient::MSClientListener::onAlreadyConnected( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onIncompatibleProtocolVersion( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onRemoteDisconnectionNotification( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onRemoteConnectionLost( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onNewIncomingConnection( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onConnectionBanned( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onConnectionAttemptFailed( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onNoFreeIncomingConnections( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onInvalidPassword( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onConnectionLost( const std::string &senderGUID ) 
{
}

void DemoClient::MSClientListener::onConnectionRequestAccepted( const std::string &senderGUID )
{
	mDemoClient->mMSServerGUID = senderGUID;
	mDemoClient->mMSClient->sendMSRequestGameServerList();
}

void DemoClient::MSClientListener::onUnknownPacket( const std::string &senderGUID ) 
{
}

/*
std::string DemoClient::MSClientListener::getMSConnectionGUID() const
{
	ATMOS_ASSERT(mMSClient);
	return mMSClient->getGUID();
}

bool DemoClient::MSClientListener::connectedToGameServer() const
{
	return mConnectedToGameServer;
}
*/

DemoClient::DemoClient( const std::string &name, int msPort, int gamePort,
	int gameServerPort ) :
mLogManager( nullptr ),
mMSClient( nullptr ),
mClientInitialized( false ),
mClient(),
mConnectedToGameServer( false ),
mGameClientListener( 0 ), 
mMSClientListener( 0 )
{	
	mGameClientListener = new GameClientListener( this );
	mMSClientListener = new MSClientListener( this, name, gamePort, gameServerPort );

	mLogManager = 
			new ATMOS::LogManager( 
#ifndef _DEBUG
			"Demo_Client.debug.log.txt"
#else
			"Demo_Client.log.txt"
#endif
			);
	
	ATMOS::NetworkConnectionInfo masterServerInfo;
	masterServerInfo.serverIP = "127.0.0.1";
	//masterServerInfo.serverIP = "184.106.161.158"; // windows server
	//masterServerInfo.serverIP = "76.11.215.58"; // home IP
	//masterServerInfo.serverIP = "192.168.0.12"; // internal IP of Mercury
	masterServerInfo.serverPort = 6677;
	masterServerInfo.clientPort = msPort;
	masterServerInfo.connectionPassword = "test";
	masterServerInfo.maxConnections = 2;
	masterServerInfo.occasionalPing = true;
	masterServerInfo.unreliableTimeout = 10000;
	masterServerInfo.shutdownTime = 500;

	mMSClient = new ATMOS::MSClient( false, name, masterServerInfo, gamePort );
	mMSClient->getNetworkManager()->addPacketListener( mMSClientListener );
	
	bool connected = false;
	for( int i = 0; i < 10 && !connected; ++i )
	{
		connected = mMSClient->connectedToMasterServer();
		Sleep( 200 );
	}

	mMSClient->sendMSRequestGameServerList();

	if( !connected )
	{
		throw std::runtime_error( "unable to connect to master server" );
	}
}

DemoClient::~DemoClient()
{
	if( mClientInitialized )
	{
		mClient.shutdown();
		mClient.removePacketListener( mGameClientListener );
	}

	if( mMSClientListener )
	{
		mMSClient->getNetworkManager()->removePacketListener( mMSClientListener );
		delete mMSClientListener;
	}

	delete mMSClient;
	delete mLogManager;
}

void DemoClient::update()
{
	if( mClientInitialized )
		mClient.update();

	mMSClient->update();
}

void DemoClient::listServers()
{
	std::cout << "SERVERS" << std::endl;
	std::cout << "---------------------------------" << std::endl;
	const std::vector<std::string> &sl = mMSClient->getServersList();
	for( std::vector<std::string>::const_iterator iter = sl.begin();
		iter != sl.end();
		++iter )
	{
		std::cout << (*iter) << std::endl;
	}
	std::cout << "---------------------------------" << std::endl;
}

void DemoClient::connectToGameServer()
{
	ATMOS_ASSERT(!mConnectedToGameServer);
	ATMOS_ASSERT(mMSClient);

	const std::vector<std::string> &sl = mMSClient->getServersList();
	if( sl.size() > 0 )
	{
		std::string serverName = *sl.begin();
		mMSClient->requestConnectionToGameServer( serverName );
	}
}

void DemoClient::disconnectFromGameServer()
{
	if( mConnectedToGameServer )
	{
		ATMOS::Packet p( ATMOS::API_UNREGISTER_CLIENT, mClient.getLocalGUID() );
		p.writeString( mClient.getLocalGUID() );
		mClient.sendPacket( &p, mGameServerGUID );

		for( int i = 0; i < 20; ++i )
		{
			Sleep( 100 );
		}

		mClient.shutdown();
		mClient.removePacketListener( mGameClientListener );
		mConnectedToGameServer = false;
	}
}

std::string DemoClient::getGameLocalGUID() const
{
	return mClient.getLocalGUID();
}

std::string DemoClient::getGameServerGUID() const
{
	return mGameServerGUID;
}

std::string DemoClient::getMSLocalGUID() const
{
	return mMSClient->getNetworkManager()->getLocalGUID();
}

std::string DemoClient::getMSServerGUID() const
{
	return mMSServerGUID;
}

void getConnectionInfoFromUser( bool masterServer, ATMOS::NetworkConnectionInfo &info );

int _tmain(int argc, _TCHAR* argv[])
{		
	try
	{
		std::string clientName;
		int msPort = 0, gamePort = 0, gameServerPort = 0;

		std::cout << "client 1 or client 2" << std::endl;

		char c = 0;
		bool done = false;
		while( !_kbhit() && !done )
		{
			c = _getch();
			switch( c )
			{
			case '1':
				clientName = "client_A";

				msPort = 1688;
				gamePort = 1051;
				gameServerPort = 1050;

				done = true;
				break;
			case '2':
				clientName = "client_B";

				msPort = 1689;				
				gamePort = 2051;
				gameServerPort = 1050;

				done = true;
				break;
			default:
				break;
			}
		}
		
		DemoClient demoClient( clientName, msPort, gamePort, gameServerPort );

		bool loop = true;
		while( loop )
		{
			demoClient.update();

			if( _kbhit() )
			{
				c = _getch();
				switch( c )
				{
				case 'q': loop = false; break;
				case 'l':
					demoClient.listServers();
					break;
				case 'c':
					//if( !demoClient.connectedToGameServer() )
						demoClient.connectToGameServer();
					break;
				case 'd':
					//if( demoClient.connectedToGameServer() )
						demoClient.disconnectFromGameServer();
					break;
				case 's':
					std::cout << "still alive" << std::endl;
					break;
				case 'g':
					std::cout 
						<< "game local GUID: " << demoClient.getGameLocalGUID() << std::endl
						<< "game server GUID: " << demoClient.getGameServerGUID() << std::endl
						<< "MS local GUID: " << demoClient.getMSLocalGUID() << std::endl
						<< "MS server GUID: " << demoClient.getMSServerGUID() << std::endl;
					break;
				}
			}
		}
	}
	catch( std::exception &error )
	{
		std::cerr << error.what() << std::endl;
		//ATMOS_LOG("error: " << error.what());
	}
	catch( ... )
	{
		std::cerr << "unknown exception" << std::endl;
		//ATMOS_LOG("error: unknown exception");
	}

	while( !_kbhit() );

	return 0;
}

void getConnectionInfoFromUser( bool masterServer, ATMOS::NetworkConnectionInfo &info )
{
	char buffer[100];
	memset( buffer, '\0', 100 );

	std::cout << (masterServer ? "master server " : "server ") << " IP: ";
	if( gets_s( buffer, 100 ) )
	{
		info.serverIP = buffer;
		if( info.serverIP.empty() )
		{
			// "184.106.161.158"; // windows server
			// "76.11.215.58"; // home IP
			info.serverIP = "127.0.0.1";
		}
	}
		
	std::cout << (masterServer ? "master server " : "server ") << " server port: ";
	if( gets_s( buffer, 100 ) )
	{
		std::string serverPort = buffer;
		if( serverPort.empty() )
		{			
			info.serverPort = masterServer ? 6677 : 1050;
		}
		else
		{
			info.serverPort = atoi( serverPort.c_str() );
		}
	}

	std::cout << (masterServer ? "master server " : "server ") << " client port: ";
	if( gets_s( buffer, 100 ) )
	{
		std::string clientPort = buffer;
		if( clientPort.empty() )
		{
			info.clientPort = masterServer ? 6688 : 1051;
		}
		else
		{
			info.clientPort = atoi( clientPort.c_str() );
		}
	}
}